﻿#include "OiPCH.hpp"

namespace Oi
{
    namespace PLScannerCore
    {
        class OPCTaskImpl : public Impl<OPCTask>
        {
        public:
            enum WriteType
            {
                WT_Heartbeat = 1,
                WT_Output,
                WT_Fixed,
            };
        public:
            QList<QPair<int, QVariant>> _wDatas;

        public:
            QMutex _mutex;
            bool _quit;

        public:
            bool _simulation;
            bool _opcEnable;
            bool _opcInspectParam;
            bool _opcInspectOutput;
            bool _opcELWidth;
            bool _opcHeartbeat;
            QString _deviceName;
            int _updateRate;
            QString _group;

        public:
            QString _formularPath;
            QString _widthPath;
            QString _thicknessPath;
            QString _widthWarnErrPath;
            QString _widthErrTolPath;
            QString _thicknessWarnErrPath;
            QString _thicknessErrTolPath;
            QString _definitionNumPath;
            QStringList _definitionListPath;
            QString _measureTypePath;
            QString _measureNumPath;
            QStringList _measureListPath;
            QString _fixedMeasurePosPath;
            QString _startMeasurePath;
            QString _switchEnablePath;
            QString _elWidthPath;

        public:
            QString _outHeartbeatPath;
            QString _outFormulaPath;
            QString _outWidthPath;
            QString _outMeasureTypePath;
            QString _outMeasureNumPath;
            QStringList _outMeasureListPath;
            QString _outFixedMeasurePath;
            QString _outResultPath;
            QStringList _outMeasureDisListPath;

        public:
            QString _formula;
            double _width;
            double _thickness;
            double _widthWarnErr;
            double _widthErrTol;
            double _thicknessWarnErr;
            double _thicknessErrTol;
            int _definitionNum;
            QList<QPointF> _definitionList;
            int _measureType;
            int _measureNum;
            QList<double> _measureList;
            double _fixedMeasurePos;
            int _startMeasureFlag;
            int _switchEnableFlag;
            double _elWidth;
        };


        OPCTask::OPCTask(QObject* parent) 
            : QThread(parent)
        {
            OI_I(OPCTask);
            
            init();
        }

        OPCTask::~OPCTask()
        {
            OI_E(OPCTask);

            exit();
        }

        void OPCTask::init()
        {
            OI_F(OPCTask);

            d->_simulation = PLScanner::instance()->simulation;
            d->_quit = false;
            auto settings = Core::OiSettings();
            d->_opcEnable = settings->value("OPC/Enable", false).toBool();
            d->_opcInspectParam = settings->value("OPC/InspectParamEnable", true).toBool();
            d->_opcInspectOutput = settings->value("OPC/InspectOutputEnable", true).toBool();
            d->_opcELWidth = settings->value("OPC/ELWidthEnable", false).toBool();
            d->_opcHeartbeat = settings->value("OPC/HeartbeatEnable", true).toBool();

            d->_deviceName = Core::OiSettings()->value("OPC/DeviceName", "Kepware.KEPServerEX.V6").toString();
            d->_updateRate = Core::OiSettings()->value("OPC/UpdateRate", 100).toInt();
            d->_group = "Default";

            d->_definitionListPath = QStringList({ "LINER.plc.rcv10",
                "LINER.plc.rcv11", "LINER.plc.rcv12", 
                "LINER.plc.rcv13", "LINER.plc.rcv14", 
                "LINER.plc.rcv15", "LINER.plc.rcv16", 
                "LINER.plc.rcv17", "LINER.plc.rcv18",
                "LINER.plc.rcv19", "LINER.plc.rcv20",
                "LINER.plc.rcv21", "LINER.plc.rcv22",
                "LINER.plc.rcv23", "LINER.plc.rcv24",
                "LINER.plc.rcv25", "LINER.plc.rcv26",
                "LINER.plc.rcv27", "LINER.plc.rcv28",
                "LINER.plc.rcv29"
            });

            d->_measureListPath = QStringList({ "LINER.plc.rcv32",
                "LINER.plc.rcv33", "LINER.plc.rcv34",
                "LINER.plc.rcv35", "LINER.plc.rcv36"
            });

            d->_outMeasureListPath = QStringList({ "LINER.plc.send5",
                "LINER.plc.send6", "LINER.plc.send7",
                "LINER.plc.send8", "LINER.plc.send9"
            });
            d->_outMeasureDisListPath = QStringList({ "LINER.plc.send13",
               "LINER.plc.send14", "LINER.plc.send15",
               "LINER.plc.send16", "LINER.plc.send17"
                });
            d->_formularPath = Core::OiSettings()->value("OPC/Formula", "LINER.plc.rcv1").toString();
            d->_widthPath = Core::OiSettings()->value("OPC/Width", "LINER.plc.rcv3").toString();
            d->_thicknessPath = Core::OiSettings()->value("OPC/Thickness", "LINER.plc.rcv4").toString();
            d->_widthWarnErrPath = Core::OiSettings()->value("OPC/WidthWarnErr", "LINER.plc.rcv5").toString();
            d->_widthErrTolPath = Core::OiSettings()->value("OPC/WidthErrTol", "LINER.plc.rcv6").toString();
            d->_thicknessWarnErrPath = Core::OiSettings()->value("OPC/ThicknessWarnErr", "LINER.plc.rcv7").toString();
            d->_thicknessErrTolPath =  Core::OiSettings()->value("OPC/ThicknessErrTol", "LINER.plc.rcv8").toString();
            d->_definitionNumPath = Core::OiSettings()->value("OPC/DefinitionNum", "LINER.plc.rcv9").toString();
            d->_definitionListPath = Core::OiSettings()->value("OPC/DefinitionList", d->_definitionListPath).toStringList();
            d->_measureTypePath = Core::OiSettings()->value("OPC/MeasureType", "LINER.plc.rcv30").toString();
            d->_measureNumPath = Core::OiSettings()->value("OPC/MeasureNum", "LINER.plc.rcv31").toString();
            d->_measureListPath = Core::OiSettings()->value("OPC/MeasureList", d->_measureListPath).toStringList();
            d->_fixedMeasurePosPath = Core::OiSettings()->value("OPC/FixedMeasurePos", "LINER.plc.rcv37").toString();
            d->_startMeasurePath = Core::OiSettings()->value("OPC/FixedMeasurePos", "LINER.plc.rcv38").toString();
            d->_switchEnablePath = Core::OiSettings()->value("OPC/FixedMeasurePos", "LINER.plc.rcv39").toString();
            d->_elWidthPath = Core::OiSettings()->value("OPC/ElWidth", "LINER.plc.rcv40").toString();

            d->_outHeartbeatPath = Core::OiSettings()->value("OPC/Formula", "LINER.plc.send0").toString();
            d->_outFormulaPath = Core::OiSettings()->value("OPC/Formula", "LINER.plc.send1").toString();
            d->_outWidthPath = Core::OiSettings()->value("OPC/Formula", "LINER.plc.send2").toString();
            d->_outMeasureTypePath = Core::OiSettings()->value("OPC/Formula", "LINER.plc.send3").toString();
            d->_outMeasureNumPath = Core::OiSettings()->value("OPC/Formula", "LINER.plc.send4").toString();
            d->_outMeasureListPath = Core::OiSettings()->value("OPC/Formula", d->_outMeasureListPath).toStringList();
            d->_outFixedMeasurePath = Core::OiSettings()->value("OPC/Formula", "LINER.plc.send10").toString();
            d->_outResultPath = Core::OiSettings()->value("OPC/Formula", "LINER.plc.send11").toString();
            d->_outMeasureDisListPath = Core::OiSettings()->value("OPC/Formula", d->_outMeasureDisListPath).toStringList();

            if(!d->_simulation && d->_opcEnable)
            {
                 start();
            }
        }

        void OPCTask::exit()
        {
            if(isRunning())
            {
                quit();
                wait();
            }
        }

        void OPCTask::run()
        {
            OI_F(OPCTask);

            bool quit = false;
            int action;
            int lcommand = 0;
            QPair<int, QVariant> output;

            if (d->_simulation || !d->_opcEnable)
            {
                return;
            }

             QSharedPointer<Util::OPC> device = Util::OPCService::instance()->add("RSLinx OPC Server", d->_deviceName);

             if (!device->isValid())
             {
                 PLScannerError::instance()->reportError(PLScannerError::ERR_OPC_CREATE_FAILED);
                 return;
             }

            device->appendGroup(d->_group, d->_updateRate, true);

            Base::List<QString> items;
            Base::List<int> errors;

            if (d->_opcInspectParam)
            {
                items.push_back(d->_formularPath);
                items.push_back(d->_widthPath);
                items.push_back(d->_thicknessPath);
                items.push_back(d->_widthWarnErrPath);
                items.push_back(d->_widthErrTolPath);
                items.push_back(d->_thicknessWarnErrPath);
                items.push_back(d->_thicknessErrTolPath);
                items.push_back(d->_definitionNumPath);
                items.insert(items.end(), d->_definitionListPath.begin(), d->_definitionListPath.end());
                items.push_back(d->_measureTypePath);
                items.push_back(d->_measureNumPath);
                items.insert(items.end(), d->_measureListPath.begin(), d->_measureListPath.end());
                items.push_back(d->_fixedMeasurePosPath);
                items.push_back(d->_switchEnablePath);
                items.push_back(d->_startMeasurePath);
            }

            if (d->_opcELWidth)
            {
                items.push_back(d->_elWidthPath);
            }
           
            if (d->_opcHeartbeat)
            {
                items.push_back(d->_outHeartbeatPath);
            }
            if (d->_opcInspectOutput)
            {
                items.push_back(d->_outFormulaPath);
                items.push_back(d->_outWidthPath);
                items.push_back(d->_outMeasureTypePath);
                items.push_back(d->_outMeasureNumPath);
                items.insert(items.end(), d->_outMeasureListPath.begin(), d->_outMeasureListPath.end());
                items.push_back(d->_outFixedMeasurePath);
                items.push_back(d->_outResultPath);
                items.insert(items.end(), d->_outMeasureDisListPath.begin(), d->_outMeasureDisListPath.end());
            }

            if(!device->appendItems(items, errors, d->_group))
            {
                PLScannerError::instance()->reportError(PLScannerError::ERR_OPC_ITEMS_APPEND_FAILED);
                OiWarning() << "Item Error:" << items;
                return;
            }

            while(!quit)
            {
                d->_mutex.lock();
                quit = d->_quit;
                action = d->_wDatas.size();
                if(action != 0)
                {
                    output = d->_wDatas.front();
                    d->_wDatas.pop_front();
                }

                d->_mutex.unlock();

                if(action != 0)
                {
                    auto type = output.first;
                    auto value = output.second;

                    if (type == OPCTaskImpl::WT_Heartbeat)
                    {
                        if (d->_opcHeartbeat)
                        {
                            int heartbeat = value.toInt();

                            Base::List<QString> names;
                            Base::List<int> outValues;
                            Base::List<int> errors;

                            names.push_back(d->_outHeartbeatPath);
                            outValues.push_back(heartbeat);

                            if (device->set(names, outValues, errors, d->_group))
                            {
                            }
                            else
                            {
                                OiWarning() << "heartbeat:" << names;
                                PLScannerError::instance()->reportError(PLScannerError::ERR_OPC_WRITE_TIMEOUT);
                            }
                        }
                        
                    }
                    else if (type == OPCTaskImpl::WT_Output)
                    {
                        if (d->_opcInspectOutput)
                        {
                            QVariantList list = value.value<QVariantList>();
                            QString specName = list[0].toString();
                            int result = list[1].toInt();
                            int measureType = 0;
                            double width = list[2].toDouble();
                            int measureNum = list[3].toInt();
                            double t1 = list.size() > 4 ? list[4].toDouble() : 0.0;
                            double t2 = list.size() > 5 ? list[5].toDouble() : 0.0;
                            double t3 = list.size() > 6 ? list[6].toDouble() : 0.0;
                            double t4 = list.size() > 7 ? list[7].toDouble() : 0.0;
                            double t5 = 0.0;
                            double t6 = list.size() > 8 ? list[8].toDouble() : 0.0;
                            double t7 = list.size() > 9 ? list[9].toDouble() : 0.0;
                            double t8 = list.size() > 10 ? list[10].toDouble() : 0.0;
                            double t9 = list.size() > 11 ? list[11].toDouble() : 0.0;
                            double t10 = list.size() > 12 ? list[12].toDouble() : 0.0;
                            int outResult = 0;
                            if (result == WorkResult::RC_Success)
                            {
                                outResult = 0;
                            }
                            else if (result == WorkResult::RC_Warning)
                            {
                                outResult = 1;
                            }
                            else
                            {
                                outResult = 2;
                            }

                            Base::List<QString> intNames;
                            Base::List<int> intOutValues;
                            Base::List<int> intErrors;

                            intNames.push_back(d->_outResultPath);
                            intNames.push_back(d->_outMeasureTypePath);
                            intNames.push_back(d->_outMeasureNumPath);

                            intOutValues.push_back(outResult);
                            intOutValues.push_back(measureType);
                            intOutValues.push_back(measureNum);

                            if (device->set(intNames, intOutValues, intErrors, d->_group))
                            {

                            }
                            else
                            {
                                OiWarning() << "outInt:" << intNames;
                                PLScannerError::instance()->reportError(PLScannerError::ERR_OPC_WRITE_TIMEOUT);
                            }

                            Base::List<QString> strNames;
                            Base::List<QString> strOutValues;
                            Base::List<int> strErrors;

                            strNames.push_back(d->_outFormulaPath);
                            strOutValues.push_back(specName);

                            if (device->set(strNames, strOutValues, strErrors, d->_group))
                            {

                            }
                            else
                            {
                                OiWarning() << "outString:" << strNames;
                                PLScannerError::instance()->reportError(PLScannerError::ERR_OPC_WRITE_TIMEOUT);
                            }

                            Base::List<QString> dbNames;
                            Base::List<double> dbOutValues;
                            Base::List<int> dbErrors;

                            dbNames.push_back(d->_outWidthPath);
                            dbNames.insert(dbNames.end(), d->_outMeasureListPath.begin(), d->_outMeasureListPath.end());

                            dbOutValues.push_back(width);
                            dbOutValues.push_back(t1);
                            dbOutValues.push_back(t2);
                            dbOutValues.push_back(t3);
                            dbOutValues.push_back(t4);
                            dbOutValues.push_back(t5);
                            dbNames.insert(dbNames.end(), d->_outMeasureDisListPath.begin(), d->_outMeasureDisListPath.end());
                            dbOutValues.push_back(t6);
                            dbOutValues.push_back(t7);
                            dbOutValues.push_back(t8);
                            dbOutValues.push_back(t9);
                            dbOutValues.push_back(t10);
                            if (device->set(dbNames, dbOutValues, dbErrors, d->_group))
                            {

                            }
                            else
                            {
                                OiWarning() << "outDouble:" << dbNames;
                                PLScannerError::instance()->reportError(PLScannerError::ERR_OPC_WRITE_TIMEOUT);
                            }
                        }
                    }
                    else if (type == OPCTaskImpl::WT_Fixed)
                    {
                        if (d->_opcInspectOutput)
                        {
                            QVariantList list = value.value<QVariantList>();

                            QString specName = list[0].toString();
                            int result = list[1].toInt();
                            int measureType = 1;
                            double value = list[2].toDouble();

                            int outResult = 0;
                            if (result == WorkResult::RC_Success)
                            {
                                outResult = 0;
                            }
                            else if (result == WorkResult::RC_Warning)
                            {
                                outResult = 1;
                            }
                            else
                            {
                                outResult = 2;
                            }

                            Base::List<QString> intNames;
                            Base::List<int> intOutValues;
                            Base::List<int> intErrors;

                            intNames.push_back(d->_outResultPath);
                            intNames.push_back(d->_outMeasureTypePath);

                            intOutValues.push_back(outResult);
                            intOutValues.push_back(measureType);

                            if (device->set(intNames, intOutValues, intErrors, d->_group))
                            {

                            }
                            else
                            {
                                OiWarning() << "outInt:" << intNames;
                                PLScannerError::instance()->reportError(PLScannerError::ERR_OPC_WRITE_TIMEOUT);
                            }

                            Base::List<QString> strNames;
                            Base::List<QString> strOutValues;
                            Base::List<int> strErrors;

                            strNames.push_back(d->_outFormulaPath);
                            strOutValues.push_back(specName);

                            if (device->set(strNames, strOutValues, strErrors, d->_group))
                            {

                            }
                            else
                            {
                                OiWarning() << "outString:" << strNames;
                                PLScannerError::instance()->reportError(PLScannerError::ERR_OPC_WRITE_TIMEOUT);
                            }

                            Base::List<QString> dbNames;
                            Base::List<double> dbOutValues;
                            Base::List<int> dbErrors;

                            dbNames.push_back(d->_outFixedMeasurePath);

                            dbOutValues.push_back(value);

                            if (device->set(dbNames, dbOutValues, dbErrors, d->_group))
                            {

                            }
                            else
                            {
                                OiWarning() << "outDouble:" << dbNames;
                                PLScannerError::instance()->reportError(PLScannerError::ERR_OPC_WRITE_TIMEOUT);
                            }
                        }

                    }
                   
                    QThread::msleep(10);
                }
                else
                {
                    QString formula;
                    double width = 0.0;
                    double thickness = 0.0;
                    double widthWarnErr = 0.0;
                    double widthErrTol = 0.0;
                    double thicknessWarnErr = 0.0;
                    double thicknessErrTol = 0.0;
                    int definitionNum = 0;
                    QList<QPointF> definitionList;
                    int measureType = 0;
                    int measureNum = 0;
                    QList<double> measureList;
                    double fixedMeasurePos = 0.0;
                    int startMeasureFlag = 0;
                    int switchEnableFlag = 0;
                    double elWidth = 0.0;

                    if (d->_opcInspectParam)
                    {
                        Base::List<QString> readStrNames;
                        Base::List<QString> readStrOut;
                        Base::List<int> readStrErrors;

                        readStrNames.push_back(d->_formularPath);

                        if (device->get(readStrNames, readStrOut, readStrErrors, d->_group))
                        {
                            formula = readStrOut[0];
                        }
                        else
                        {
                            OiWarning() << "InString:" << readStrNames;
                            PLScannerError::instance()->reportError(PLScannerError::ERR_OPC_READ_TIMEOUT);
                        }
                        /*
                                            Base::List<QString> readIntNames;
                                            Base::List<int> readIntOut;
                                            Base::List<int> readIntErrors;

                                            readIntNames.push_back(d->_definitionNumPath);
                                            readIntNames.push_back(d->_measureTypePath);
                                            readIntNames.push_back(d->_measureNumPath);
                                            readIntNames.push_back(d->_startMeasurePath);
                                            readIntNames.push_back(d->_switchEnablePath);

                                            if(device->get(readIntNames, readIntOut, readIntErrors, d->_group))
                                            {
                                                definitionNum = readIntOut[0];
                                                measureType = readIntOut[1];
                                                measureNum = readIntOut[2];
                                                startMeasureFlag = readIntOut[3];
                                                switchEnableFlag = readIntOut[3];

                                            }
                                            else
                                            {
                                                OiWarning() << "InInt:" << readIntNames;
                                                PLScannerError::instance()->reportError(PLScannerError::ERR_OPC_READ_TIMEOUT);
                                            }

                                            Base::List<QString> readDoubleNames;
                                            Base::List<double> readDoubleOut;
                                            Base::List<int> readDoubleErrors;

                                            readDoubleNames.push_back(d->_widthPath);
                                            readDoubleNames.push_back(d->_thicknessPath);
                                            readDoubleNames.push_back(d->_widthWarnErrPath);
                                            readDoubleNames.push_back(d->_widthErrTolPath);
                                            readDoubleNames.push_back(d->_thicknessWarnErrPath);
                                            readDoubleNames.push_back(d->_thicknessErrTolPath);
                                            readDoubleNames.push_back(d->_fixedMeasurePosPath);

                                            for (int i = 0; i < definitionNum; i++)
                                            {
                                                readDoubleNames.push_back(d->_definitionListPath[i * 2]);
                                                readDoubleNames.push_back(d->_definitionListPath[i * 2 + 1]);
                                            }

                                            for (int i = 0; i < measureNum; i++)
                                            {
                                                readDoubleNames.push_back(d->_measureListPath[i]);
                                            }

                                            if (device->get(readDoubleNames, readDoubleOut, readDoubleErrors, d->_group))
                                            {
                                                width = readDoubleOut[0];
                                                thickness = readDoubleOut[1];
                                                widthWarnErr = readDoubleOut[2];
                                                widthErrTol = readDoubleOut[3];
                                                thicknessWarnErr = readDoubleOut[4];
                                                thicknessErrTol = readDoubleOut[5];
                                                fixedMeasurePos = readDoubleOut[6];

                                                for (int i = 0; i < definitionNum; i++)
                                                {
                                                    definitionList.append(QPointF(readDoubleOut[ 7 + i * 2], readDoubleOut[8 + i * 2]));
                                                }

                                                int startIndex = 7 + definitionNum * 2;

                                                for (int i = 0; i < measureNum; i++)
                                                {
                                                    measureList.push_back(readDoubleOut[startIndex + i]);
                                                }

                                            }
                                            else
                                            {
                                                OiWarning() << "InDouble:" << readDoubleNames;
                                                PLScannerError::instance()->reportError(PLScannerError::ERR_OPC_READ_TIMEOUT);
                                            }*/

                    }

                    if (d->_opcELWidth)
                    {
                        Base::List<QString> reaDoubleNames;
                        Base::List<double> readDoubleOut;
                        Base::List<int> readDoubleErrors;

                        reaDoubleNames.push_back(d->_elWidthPath);

                        if (device->get(reaDoubleNames, readDoubleOut, readDoubleErrors, d->_group))
                        {
                            elWidth = readDoubleOut[0];
                        }
                        else
                        {
                            OiWarning() << "InDouble:" << reaDoubleNames;
                            PLScannerError::instance()->reportError(PLScannerError::ERR_OPC_READ_TIMEOUT);
                        }
                    }
                    d->_mutex.lock();

                    d->_formula = formula;
                    d->_width = width;
                    d->_thickness = thickness;
                    d->_widthWarnErr = widthWarnErr;
                    d->_widthErrTol = widthErrTol;
                    d->_thicknessWarnErr = thicknessWarnErr;
                    d->_thicknessErrTol = thicknessErrTol;
                    d->_definitionNum = definitionNum;
                    d->_definitionList = definitionList;
                    d->_measureType = measureType;
                    d->_measureNum = measureNum;
                    d->_measureList = measureList;
                    d->_fixedMeasurePos = fixedMeasurePos;
                    d->_startMeasureFlag = startMeasureFlag;
                    d->_switchEnableFlag = switchEnableFlag;
                    d->_elWidth = elWidth;
                  
                    d->_mutex.unlock();

                    QThread::msleep(10);
                }
            }

            Util::PLCService::instance()->exit();
        }

        void OPCTask::quit()
        {
            OI_F(OPCTask);
            QMutexLocker lock(&d->_mutex);
            d->_quit = true;
        }

        void OPCTask::start()
        {
            OI_F(OPCTask);
            d->_mutex.lock();
            d->_quit = false;
            d->_wDatas.clear();
            d->_mutex.unlock();

            QThread::start();
        }

        bool OPCTask::write(const WorkResult::Result& ouput)
        {
            OI_F(OPCTask);

            if (d->_simulation || !d->_opcEnable)
            {
                return true;
            }

            if (!isRunning())
            {
                return false;
            }

            QVariantList values;
            values.append(ouput.params.specName);
            values.append(ouput.result);
            values.append(ouput.data["tolWidth2"]);
            auto mtp = ouput.data["measureThickness"].value<QList<QPointF>>();
            values.append(mtp.size());
            for (int i = 0; i < mtp.size(); i++)
            {
                values.append(mtp[i].y());
            }
            values.append(ouput.data["ThicknessDis1"]);
            values.append(ouput.data["ThicknessDis2"]);
            values.append(ouput.data["ThicknessDis3"]);
            values.append(ouput.data["ThicknessDis4"]);
            values.append(ouput.data["ThicknessDis"]);
            QMutexLocker lock(&d->_mutex);
            d->_wDatas.push_back(QPair<int, QVariant>(OPCTaskImpl::WT_Output, values));

            return true;
        }

        bool OPCTask::write(const QString name, const double value, int result)
        {
            OI_F(OPCTask);

            if (d->_simulation || !d->_opcEnable)
            {
                return true;
            }

            if (!isRunning())
            {
                return false;
            }

            QVariantList values;
            values.append(name);
            values.append(result);
            values.append(value);

            QMutexLocker lock(&d->_mutex);
            d->_wDatas.push_back(QPair<int, QVariant>(OPCTaskImpl::WT_Fixed, values));

            return true;
        }

        bool OPCTask::readSpecName(QString& name)
        {
            OI_F(OPCTask);

            QString formula;

            d->_mutex.lock();
            formula = d->_formula;
            d->_mutex.unlock();

            if (formula.isEmpty())
            {
                OiWarning() << "配方名为空，配方切换不启动";
                return false;
            }

            name = formula;
            return true;
        }

        bool OPCTask::readParams(ProductParams& params)
        {
            OI_F(OPCTask);

            QString formula;
            double width = 0.0;
            double thickness;
            double widthWarnErr;
            double widthErrTol;
            double thicknessWarnErr;
            double thicknessErrTol;
            int definitionNum;
            QList<QPointF> definitionList;
            int measureType;
            int measureNum;
            QList<double> measureList;
            double fixedMeasurePos;
            int switchEnableFlag = 0;

            d->_mutex.lock();
            formula = d->_formula;
            width = d->_width;
            thickness = d->_thickness;
            widthWarnErr = d->_widthWarnErr;
            widthErrTol = d->_widthErrTol;
            thicknessWarnErr = d->_thicknessWarnErr;
            thicknessErrTol = d->_thicknessErrTol;
            definitionNum = d->_definitionNum;
            definitionList = d->_definitionList;
            measureType = d->_measureType;
            measureNum = d->_measureNum;
            measureList = d->_measureList;
            fixedMeasurePos = d->_fixedMeasurePos;
            switchEnableFlag = d->_switchEnableFlag;
            d->_mutex.unlock();

            if (switchEnableFlag == 0)
            {
                //OiWarning() << "<switchEnableFlag = false>,配方切换不启动";
                return false;
            }
            if (width == 0.0 || formula.isEmpty())
            {
                OiWarning() << "<width = " << width << ",formula = " << formula<< ">,配方切换不启动";
                return false;
            }

            QList<DefinitionPoint> definitionPoints;
            for (auto dpp : definitionList)
            {
                DefinitionPoint dp;
                dp.distance = fabs(dpp.x());
                dp.type = DT_FullWidth;
                if (dpp.x() <= 0)
                {
                    dp.thicknessLeft = fabs(dpp.y());
                    dp.thicknessRight = 0.0;
                }
                else
                {
                    dp.thicknessLeft = 0.0;
                    dp.thicknessRight = fabs(dpp.y());
                }
            }

            params = ProductParams(formula, width, thickness, measureType
                , definitionPoints
                , measureList
                , fixedMeasurePos
                , widthErrTol
                , widthWarnErr
                , thicknessErrTol
                , thicknessWarnErr);

            return true;
        }

        bool OPCTask::readStatus(int& flag)
        {
            OI_F(OPCTask);

            d->_mutex.lock();
            flag = d->_startMeasureFlag;
            d->_mutex.unlock();

            return true;

        }

        bool OPCTask::heartbeat(int heartbeat)
        {
            OI_F(OPCTask);

            if (d->_simulation || !d->_opcEnable)
            {
                return true;
            }

            if (!isRunning())
            {
                return false;
            }
  

            QMutexLocker lock(&d->_mutex);
            d->_wDatas.push_back(QPair<int, QVariant>(OPCTaskImpl::WT_Heartbeat, heartbeat));

            return true;
        }

        bool OPCTask::readELWidth(double& value)
        {
            OI_F(OPCTask);

            d->_mutex.lock();
            value = 0.1 * d->_elWidth;
            d->_mutex.unlock();

            return true;
        }

        OPCTask* OPCTask::instance()
        {
            static OPCTask s_plc;
            return &s_plc;
        }

    }
}